package cn.ges.movie.config.aop

import cn.ges.js.JsHelper
import cn.ges.type.BlankHelper
import com.baomidou.mybatisplus.core.metadata.IPage
import com.baomidou.mybatisplus.extension.plugins.pagination.Page
import com.ges.common.vo.ReturnJsonVO
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Pointcut
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.core.Ordered
import org.springframework.core.annotation.Order
import org.springframework.stereotype.Component


/**
 * 自动转换所有LIST和IPAGE中的LONG值为STRING
 *
 * @author gespent@163.com
 * @date 2020年9月18日 17:20:18
 */
@Component
@Aspect
@Order(value = Ordered.LOWEST_PRECEDENCE)
open class JsCastAop {
    val log: Logger = LoggerFactory.getLogger(this.javaClass)

    @Suppress("UNCHECKED_CAST")
    @Around(value = "allControllerPointCut()", argNames = "joinPoint")
    @Throws(Throwable::class)
    fun pageCheck(joinPoint: ProceedingJoinPoint): ReturnJsonVO {
        // 因为切面的原因 返回类一定是 ReturnJsonVO
        val proceed = joinPoint.proceed() as ReturnJsonVO
        // 如果data 为空直接返回
        val data = proceed.data ?: return proceed

        when (data) {
            is ArrayList<*> -> {
                if (BlankHelper.listIsBlank(data)) {
                    return proceed
                }
                // 进行转换
                val any = data[0]::class.java
                if (any == HashMap::class.java) {
                    // 不处理 HashMap
                    return proceed
                }
                val value: ArrayList<Any?> = data as ArrayList<Any?>
                val list = value.filterNotNull() as ArrayList<Any>

                val castListLongField2String = JsHelper.castListLongField2String(
                    list, any as Class<Any>)
                proceed.data = castListLongField2String
                return proceed
            }
            is IPage<*> -> {
                val records = data.records
                if (BlankHelper.listIsBlank(records)) {
                    return proceed
                }
                val java = records[0]::class.java
                if (java == HashMap::class.java) {
                    // 不处理 HashMap
                    return proceed
                }

                val castPageLongField2String = try {
                    castPageLongField2String(data as IPage<Any>, java as Class<Any>)
                } catch (e: Exception) {
                    proceed.data
                }
                proceed.data = castPageLongField2String
                return proceed
            }
            else -> {
                return proceed
            }
        }

    }


    fun <T : Any> castPageLongField2String(source: IPage<T>,
                                           clazz: Class<T>): IPage<*>? {
        val records = source.records as ArrayList<T>? ?: return null

        val value: ArrayList<T?> = records as ArrayList<T?>
        val list = value.filterNotNull() as ArrayList<T>

        val castListLongField2String = JsHelper.castListLongField2String(list, clazz)
        return clonePage(source, castListLongField2String)
    }

    companion object {
        fun <T> clonePage(source: IPage<*>, list: List<T>?): IPage<T>? {
            val target = Page<T>()
            target.total = source.total
            target.current = source.current
            target.size = source.size
            target.records = list
            return target
        }
    }


    /**
     * 所有controller 含有@RequestMapping注解的方法 且返回值为ReturnJsonVO
     */
    @Pointcut(value = "execution(com.ges.common.vo.ReturnJsonVO *..*(..)) && @annotation(org.springframework.web.bind.annotation.RequestMapping)")
    fun allControllerPointCut() {
        // 因为是后台应用 访问量不大 不进行注解进行差异化管理
    }
}